﻿using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using ColorApplication.BusinessLayer;
using ColorApplication.Constants;
using ColorApplication.Helper;

namespace ColorApplication.color
{
    public partial class ReportDetails : System.Web.UI.Page
    {
        private const int TopCount = 10;

        protected void Page_Load(object sender, EventArgs e)
        {
            if (Request.QueryString["id"] != null && Request.QueryString["id"] == ConfigurationManager.AppSettings["AdminID"].ToString())
            {
                if (!string.IsNullOrEmpty(CacheKey))
                {
                    DisplayFilterCriteria();

                    BindDataToReport();
                }
            }
        }

        private void DisplayFilterCriteria()
        {
            litStartEndDate.Text = string.Format("<b>Start date:</b> {0}, <b>End date:</b> {1}", Request.QueryString["sd"] ?? "",
                                                 Request.QueryString["ed"] ?? "");
            litSelectedOpt.Text = string.Format("<b>Selected Option:</b> {0}", SelectOptionLiteral);
            litAttsFamily.Text = string.Format("<b>Attribute family:</b> {0}", AttFamily == "" ? "All" : AttFamily);
        }

        protected string SelectOptionLiteral
        {
            get
            {
                switch (SelectOptionValue)
                {
                    case 0:
                        return "All options";
                        break;
                    case 1:
                        return "One image";
                        break;
                    case 2:
                        return "Two image";
                        break;
                    default:
                        specificUrl.Text = string.Format("<br /><b>Specific URL:</b> {0}", AnalysisUrl == "" ? "All URLs" : AnalysisUrl);
                        return "From URL";
                        break;
                }
            }
        }

        private void BindDataToReport()
        {
            var selectedOpt = SelectOptionValue;
            var analysisUrl = AnalysisUrl;
            var attFamily = AttFamily;

            var dt = new DataTable();
            if (Request.QueryString["sd"] == "" && Request.QueryString["ed"] == "")
            {
                dt = GetAdminReportsByDate(null, null, selectedOpt, analysisUrl, attFamily);
            }
            else //if dates are filled
            {
                DateTime fromdate = StartDate;
                DateTime todate = EndDate;
                dt = GetAdminReportsByDate(fromdate, todate, selectedOpt, analysisUrl, attFamily);
            }

            if (dt != null && dt.Rows.Count > 0)
            {
                var listReport = GetReportFromDataTable(dt);
                Session[SessionCacheKey] = listReport;
                ExportButton.Enabled = true;

                ReportGridView.DataSource = listReport;
                ReportGridView.DataBind();
                ReportGridView.Visible = true;

                BindDataForHeader(listReport);
            }
            else
            {
                ReportGridView.DataSource = new List<ReportObject>();
                ReportGridView.DataBind();
            }
        }

        protected string AttFamily { get { return Request.QueryString["af"] ?? ""; } }

        protected string AnalysisUrl
        {
            get { return Request.QueryString["au"] ?? ""; }
        }

        protected string SessionCacheKey
        {
            get { return Request.QueryString["ck"] ?? ""; }
        }

        protected int SelectOptionValue
        {
            get
            {
                var so = Request.QueryString["so"] ?? "0";
                return int.Parse(so);
            }
        }

        protected DateTime StartDate
        {
            get
            {
                var sdText = Request.QueryString["sd"] ?? "";
                if (string.IsNullOrEmpty(sdText)) return new DateTime(2000, 01, 01);
                return DateTime.ParseExact(sdText, "dd-MM-yyyy", null);
            }
        }

        protected DateTime EndDate
        {
            get
            {
                var edText = Request.QueryString["ed"] ?? "";
                if (string.IsNullOrEmpty(edText)) return new DateTime(2000, 01, 01);
                return DateTime.ParseExact(edText, "dd-MM-yyyy", null);
            }
        }

        private void BindDataForHeader(List<ReportObject> listReport)
        {
            if (listReport != null && listReport.Count > 0)
            {
                tableTotalSection.Visible = true;

                lblNumberOfAnan.Text = listReport.Count.ToString();
                int noOfAnalyze;
                string noOfAnaTypes;
                decimal avgOfSize, avgPerMatch, avgExpectedChosen, avgMatchingFromExpect;

                CalculateReportHeaderInfo(listReport, out noOfAnalyze, out noOfAnaTypes, out avgOfSize, out avgPerMatch,
                                          out avgExpectedChosen,
                                          out avgMatchingFromExpect);

                lblNumberOfAnan.Text = noOfAnalyze.ToString();
                lblNumberOfType.Text = noOfAnaTypes;
                lblAverageOfSize.Text = avgOfSize.ToString("0.00");
                lblAvgPerMatch.Text = avgPerMatch.ToString("0.00");
                lblAvgExpectedAttrs.Text = avgExpectedChosen.ToString("0.00");
                lblAvgMatchingNumber.Text = avgMatchingFromExpect.ToString("0.00");

                lblTopExpectedResults.Text = GetExpectedResultsForHeader(listReport);
                lblTopFoundResults.Text = GetFoundResultsForHeader(listReport);
            }
        }

        private string GetFoundResultsForHeader(List<ReportObject> listReport)
        {
            var results = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);

            foreach (var reportObject in listReport)
            {
                var expectedString = reportObject.SummaryResults.Split('|');

                foreach (var s in expectedString)
                {
                    var wantedAttr = s.Split('-')[0].Trim();
                    if (!string.IsNullOrEmpty(wantedAttr) &&
                        wantedAttr.IndexOf("Others", StringComparison.OrdinalIgnoreCase) != 0)
                    {
                        if (results.ContainsKey(wantedAttr))
                        {
                            results[wantedAttr] = results[wantedAttr] + 1;
                        }
                        else
                        {
                            results[wantedAttr] = 1;
                        }
                    }
                }
            }

            var sortedDict = from entry in results orderby entry.Value descending select entry;

            var returnedValue = string.Empty;
            foreach (var keyValuePair in sortedDict.Take(TopCount))
            {
                returnedValue += string.Format("{0}: {1},", keyValuePair.Key, keyValuePair.Value);
            }

            return returnedValue.TrimEnd(',');
        }

        private string GetExpectedResultsForHeader(List<ReportObject> listReport)
        {
            var results = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);

            foreach (var reportObject in listReport)
            {
                var expectedString = reportObject.WantedFamilyLists.Split(',');

                foreach (var s in expectedString)
                {
                    var wantedAttr = s.Split(':')[0].Trim();
                    if (results.ContainsKey(wantedAttr))
                    {
                        results[wantedAttr] = results[wantedAttr] + 1;
                    }
                    else
                    {
                        results[wantedAttr] = 1;
                    }
                }
            }

            var sortedDict = from entry in results orderby entry.Value descending select entry;

            var returnedValue = string.Empty;
            foreach (var keyValuePair in sortedDict.Take(TopCount))
            {
                returnedValue += string.Format("{0}: {1},", keyValuePair.Key, keyValuePair.Value);
            }

            return returnedValue.TrimEnd(',');
        }

        //Analyze a. sum of matched attributes – 30%, matching: 2 of 3 expected.
        //Analyze b. sum of matched attributes – 20%, matching: 1 of 2 expected.
        //Analyze c. sum of matched attributes – 46%, matching: 1 of 3 expected
        //Analyze d. sum of matched attributes – 15%, matching: 1 of 1 expected.
        //average percentage match of all lines in the report è  30% + 20% + 46% + 15% = 111%  è 111 / 4 (lines) = 27.75%  <== OPTION 1
        //average number of how many expected attributes were chosen è 3 (expected) + 2 + 3 + 1 = 9 è 9 / 4 (lines) = 2.25 <== OPTION 2
        //average number of matching number of found attributes from expected attributes è 2/3 + 1/2 + 1/3 +1/1 = 2.5 è 2.5 / 4 (lines) = 0.625 <== OPTION 3
        private void CalculateReportHeaderInfo(List<ReportObject> listReport, out int noOfAnalyze, out string noOfAnaTypes,
            out decimal avgOfSize, out decimal avgPerMatch, out decimal avgExpectedChosen, out decimal avgMatchingFromExpect)
        {
            int optTwoCount = 0;
            int optOneCount = 0;
            int optThreeCount = 0;
            decimal sumOfSize = 0;
            decimal sumOfMatchingPercent = 0;
            decimal sumOption3 = 0;
            int sumOfExpectedAttrCount = 0;

            int NoOfNonNumberOfExpected = 0;
            foreach (var reportObject in listReport)
            {
                if (reportObject.SelectedOption == AnalysisOption.OnePicture)
                {
                    optOneCount += 1;
                }
                else if (reportObject.SelectedOption == AnalysisOption.TwoPicture)
                {
                    optTwoCount += 1;
                }
                else
                {
                    optThreeCount += 1;
                }

                sumOfSize += reportObject.Size;
                sumOfMatchingPercent += reportObject.SumOfMatching;
                sumOfExpectedAttrCount += reportObject.NumberOfExpected;

                if (reportObject.NumberOfExpected > 0)
                {
                    sumOption3 += (decimal)reportObject.NumberOfMatching / reportObject.NumberOfExpected;
                }
                else
                {
                    NoOfNonNumberOfExpected += 1;
                }
            }

            noOfAnalyze = listReport.Count; // -(optTwoCount / 2);
            noOfAnaTypes = string.Format("One pic: {0}<br/>Two pic: {1}<br/>URL: {2}", optOneCount, optTwoCount,
                                         optThreeCount);
            avgOfSize = sumOfSize / listReport.Count;

            avgPerMatch = sumOfMatchingPercent / noOfAnalyze;

            avgExpectedChosen = (decimal)sumOfExpectedAttrCount / noOfAnalyze;

            var numberOfRealAna = noOfAnalyze - NoOfNonNumberOfExpected;
            if (numberOfRealAna > 0)
            {
                avgMatchingFromExpect = sumOption3 / (noOfAnalyze - NoOfNonNumberOfExpected);
            }
            else
            {
                avgMatchingFromExpect = 0;
            }
        }

        private List<ReportObject> GetReportFromDataTable(DataTable dataTable)
        {
            var results = new List<ReportObject>();
            foreach (DataRow row in dataTable.Rows)
            {
                var reportObject = new ReportObject
                {
                    Id = SQLHelper.GetIntValue(row["Id"]),
                    AnalysisDate = SQLHelper.GetDateTimeValue(row["Date"]),
                    PictureName = row["PictureName"].ToString(),
                    Size = SQLHelper.GetDecimalValue(row["Size"]),
                    PaymentTransactionId = row["PaymentTransactionId"].ToString(),
                    PaymentDetails = row["PaymentDetails"].ToString(),
                    PaymentStatus = SQLHelper.GetBoolValue(row["PaymentStatus"]),
                    SelectedOption = Converter.ConvertAnalysisOpt(row["SelectedOption"]),
                    WantedFamilyLists = row["WantedFamilyLists"].ToString(),
                    AnalysisUrl = row["AnalysisUrl"].ToString(),
                    SummaryResults = row["SummaryResults"].ToString(),
                    MatchingAttrs = row["MatchingAttributes"].ToString(),
                    MarksOfWantedFamilies = SQLHelper.GetDecimalValue(row["MarksOfWantedFamilies"]),
                    NumberOfMatching = SQLHelper.GetIntValue(row["NumberOfMatching"]),
                    ExpectedAttrsCount = SQLHelper.GetIntValue(row["ExpectedAttrsCount"]),
                    PieFileName = row["FileNameString"].ToString()
                };

                results.Add(reportObject);
            }
            return results;
        }

        //Get report between dates from table AdminReport
        public DataTable GetAdminReportsByDate(DateTime? fromdate, DateTime? todate, int selectedOption = 0, string analysisUrl = "",
            string attFamily = "")
        {
            using (var con = new SqlConnection())
            {
                var startDateParam = new SqlParameter("@StartDate", SqlDbType.DateTime) { Direction = ParameterDirection.Input, Value = fromdate };
                var endDateParam = new SqlParameter("@EndDate", SqlDbType.DateTime) { Direction = ParameterDirection.Input, Value = todate };
                var selectedOptionParam = new SqlParameter("@SelectedOption", SqlDbType.SmallInt) { Direction = ParameterDirection.Input, Value = selectedOption };
                var analysisUrlParam = new SqlParameter("@AnalysisUrl", SqlDbType.NVarChar, 150) { Direction = ParameterDirection.Input, Value = analysisUrl };
                var attsParam = new SqlParameter("@AttributeFamily", SqlDbType.NVarChar, 200) { Direction = ParameterDirection.Input, Value = attFamily };
                SqlParameter[] parameters ={
                                               startDateParam, endDateParam, selectedOptionParam, analysisUrlParam, attsParam
                                          };
                SqlCommand cmd = SQLHelper.GetCommand(con, "GetAdminReportsByDate", parameters);
                con.Open();
                var ds = new DataSet();
                SqlDataAdapter sqldataadapter = new SqlDataAdapter(cmd);
                sqldataadapter.Fill(ds);
                con.Close();
                return ds.Tables[0];
            }
        }

        protected void ExportToExcel(object sender, EventArgs e)
        {
            var listReport = GetExcelObjectFromSession();

            //Create a dummy GridView
            var gridView1 = new GridView { AllowPaging = false, DataSource = listReport };
            gridView1.DataBind();

            var filename = GetExcelFileName();

            Response.Clear();
            Response.Buffer = true;
            Response.AddHeader("content-disposition", string.Format("attachment;filename={0}", filename));
            Response.Charset = "";
            Response.ContentType = "application/vnd.ms-excel";
            var sw = new StringWriter();
            var hw = new HtmlTextWriter(sw);

            for (int i = 0; i < gridView1.Rows.Count; i++)
            {
                gridView1.Rows[i].Attributes.Add("class", "textmode");
            }
            gridView1.RenderControl(hw);

            //style to format numbers to string
            const string style = @"<style> .textmode { mso-number-format:\@; } </style>";
            Response.Write(style);
            //Response.Output.Write(string.Format("Number of analyzes: {0}", lblNumberOfAnan.Text));
            //Response.Output.Write(string.Format("Number of analysis types: {0}", lblNumberOfType.Text));
            Response.Output.Write(sw.ToString());
            Response.Flush();
            Response.End();
        }

        private List<ExcelObject> GetExcelObjectFromSession()
        {
            var results = new List<ExcelObject>();

            var listReport = Session[SessionCacheKey] as List<ReportObject>;
            if (listReport != null)
            {
                foreach (var reportObject in listReport)
                {
                    var excelObject = new ExcelObject();
                    excelObject.AnalysisDate = reportObject.AnalysisDate;
                    excelObject.AnalysisUrl = reportObject.AnalysisUrl;
                    excelObject.MatchingAttrs = reportObject.MatchingAttrs.Replace("</br>", "");
                    excelObject.NumberOfMatchingPerExpected = string.Format("'{0}/{1}", reportObject.NumberOfMatching,
                                                                            reportObject.NumberOfExpected);
                    excelObject.PictureName = reportObject.PictureName;
                    excelObject.SelectedOption = reportObject.SelectedOptionLiteral;
                    excelObject.SumOfMatching = reportObject.SumOfMatching;
                    excelObject.SummaryResults = reportObject.SummaryResults.Replace('|', ',');
                    excelObject.WantedFamilyLists = reportObject.WantedFamilyLists;
                    results.Add(excelObject);
                }
            }

            return results;
        }

        private string GetExcelFileName()
        {
            if (string.IsNullOrEmpty(StartDate.ToString()) && string.IsNullOrEmpty(EndDate.ToString()))
            {
                return "NoDate_Report.xls";
            }
            return string.Format("{0}_{1}_Report.xls", StartDate.ToString("yyyyMMdd"), EndDate.ToString("yyyyMMdd"));
        }

        protected string CacheKey
        {
            get
            {
                return Request.QueryString["ck"] ?? string.Empty;
            }
        }

        protected void ReportGridView_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            if (e.Row.RowType == DataControlRowType.DataRow)
            {
                var dataItem = e.Row.DataItem as ReportObject;
                if (dataItem != null)
                {
                    var lblAnalysisDate = e.Row.FindControl("lblAnalysisDate") as Label;
                    lblAnalysisDate.Text = dataItem.AnalysisDate.ToString("dd-MM-yyyy");

                    var lblSelectedOpt = e.Row.FindControl("lblSelectedOpt") as Label;
                    lblSelectedOpt.Text = dataItem.SelectedOptionLiteral;

                    var lblUrl = e.Row.FindControl("lblUrl") as Label;
                    RefineLabelToDisplay(lblUrl, dataItem.AnalysisUrl, 300);

                    var lblPictureName = e.Row.FindControl("lblPictureName") as Label;
                    var picName = dataItem.PictureName;
                    RefineLabelToDisplay(lblPictureName, picName, 20);

                    var lblExpectedResults = e.Row.FindControl("lblExpectedResults") as Label;
                    lblExpectedResults.Text = dataItem.WantedFamilyLists.Replace(",", "<br/>");

                    var lblSummaryResults = e.Row.FindControl("lblSummaryResults") as Label;
                    lblSummaryResults.Text = dataItem.SummaryResults.Replace("|", "<br />");

                    var lblMatchingAttrs = e.Row.FindControl("lblMatchingAttrs") as Label;
                    lblMatchingAttrs.Text = dataItem.MatchingAttrs.Replace(",", "<br />");

                    var lblMatchingPerExpected = e.Row.FindControl("lblMatchingPerExpected") as Label;
                    if (lblMatchingPerExpected != null)
                    {
                        lblMatchingPerExpected.Text = dataItem.NumberOfMatchingPerExpected;
                    }

                    var lblSumOfMatching = e.Row.FindControl("lblSumOfMatching") as Label;
                    if (lblSumOfMatching != null)
                    {
                        lblSumOfMatching.Text = string.Format("{0}%", dataItem.SumOfMatching);
                    }
                }
            }
        }

        private static void RefineLabelToDisplay(Label lbl, string value, int maxLength)
        {
            if (value.Length > maxLength)
            {
                lbl.Text = value.Substring(0, maxLength - 4) + "...";
                lbl.Attributes.Add("title", string.Format("{0}", value));
            }
            else
            {
                lbl.Text = value;
            }
        }
    }
}